home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-10-22 | 77.7 KB | 2,318 lines | [TEXT/MWPS] |
- {
- { CopyBits Demo.p
- {
- { Implemented in Oct 1995 using Metrowerks CW6.
- { Converted from C code written in May 1995 using
- { Metrowerks CodeWarrior v5.
- {
- { This Pascal CopyBits Demo project v3.1P is by Bill Catambay.
- { The orginal C CopyBits Demo project v3.1 was by Kenneth Worley.
- {
- { This code is Copyright 1995. All Rights Reserved.
- { You may use this code in any project of your own. You may also
- { redistribute this project to anyone else as long as 1) all the
- { project files (including documentation files) are kept together,
- { and 2) nothing is charged for the project.
- {
- { I really don't know what the rules are for C code converted to
- { Pascal as far as permission, licensing, and all that garbage.
- { If you have any information to shed light on this subject for me,
- { please E-mail me at Catambay@aol.com (and I thank you in advance).
- {
- {Worley notes:
- { This is a tutorial project that demonstrates the use of
- { CopyBits and offscreen Graphics Worlds (GWorlds). It shows
- { several instances of copying images to and from offscreen
- { graphics worlds using CopyBits, provides several macros that
- { make the process a little easier, shows an example of
- { drawing into an offscreen graphics world and how that can
- { improve onscreen animation, and it demonstrates a "fade"
- { using CopyBits to fade a portion of the screen to black.
- {
- { In a nutshell, the app puts up a dialog that shows two
- { "source" pictures (1 & 2) and a destination area. Clicking
- { on the "Copy" buttons above each of the source pictures
- { causes the picture to be copied to the destination area.
- { Picture 1 is labelled as "flickery animation" and picture 2
- { is labelled as "smooth animation." When you put the cursor
- { over each picture, you should see a difference in how a
- { colored circle is animated over the picture. You should
- { occasionally see the background "flicker" through on
- { picture 1, but not on picture 2 because it uses an
- { intermediary GWorld to draw in.
- {
- { The Fade to black button over the destination area will
- { cause that area to fade to black from whatever happens to
- { be in there. It does this by repeatedly copying a gray
- { rectangle from a GWorld into the destination area using
- { the subPin transfer mode of CopyBits. The erase button
- { erases the destination area.
- {
- { The Fade picture buttons cause the picture under the
- { button to be faded into whatever is currently in the
- { destination area. This is accomplished using CopyBits'
- { blend transfer mode.
- {
- {Conversion notes:
- { Of course, all the standard C to Pascal translation stuff
- { applies. Additionally, there are some pointer stuff I had to
- { tweak to get this working in Pascal. I also had to play with
- { the RGBColor records sometimes, because in Pascal they are treated
- { as integers, but in C they are treated as unsigned (I'm talking
- { about the components of course).
- {
- { Here's as example of C to Pascal translation which fuels my love for Pascal:
- {
- { As originally done in C:
- { LocalToGlobal(* (Point*) &(offscreenRect.top));
- { LocalToGlobal(* (Point*) &(offscreenRect.bottom));
- {
- { As translated into Pascal:
- { LocalToGlobal(offscreenRect.topleft);
- { LocalToGlobal(offscreenRect.botRight);
- {
- { Got rid of most of the C macros, converting just one of them, WinBitMap,
- { into a pascal function. Also converted to pascal are three other
- { C libraries. They have been implemented as UNITs: MyAlerts, MyDialogUtils,
- { and MySystemUtils. And there was some other stuff I had to do to get
- { this working, but I'm too tired now to try and remember it all. Just enjoy
- { the code, and I hope you learn lots of stuff!
- {
- { Questions? Comments? Praise? Criticism? Jobs? If it has
- { to do with the Pascal code included here, write to
- { Bill Catambay at catambay@aol.com, and if it has to do with
- { the original C code, write to Kenneth Worley at KNEworley@aol.com.
- }
- Program CopyBitsDemo;
-
- Uses
- QDOffscreen, Dialogs, PictUtils, SegLoad, ToolUtils, DiskInit,
- MyAlerts, MyDialogUtils, MySystemUtils;
-
- Const
- { The main dialog's resource ID. }
- kMainDlgID = 128;
- { The two pictures in the main dialog. }
- kPict1ID = 128;
- kPict2ID = 129;
- { Item numbers in the main dialog. }
- kMainDlgQuit = 1;
- kMainDlgCopyOne = 2;
- kMainDlgFadeOne = 3;
- kMainDlgCopyTwo = 4;
- kMainDlgFadeTwo = 5;
- kMainDlgErase = 6;
- kMainDlgPICTOne = 8;
- kMainDlgPICTTwo = 9;
- kMainDlgDestPICT = 10;
- kMainDlgFadeSpeed = 15;
- kMainDlgFullScreen = 20;
- kMainDlgPixelize = 21;
- kMainDlgDepixelizeOne = 22;
- kMainDlgDepixelizeTwo = 23;
- kMainDlgFadeToBlack1 = 7;
- kMainDlgFadeToBlack2 = 24;
- kMainDlgFadeToBlack3 = 25;
- kMainDlgBlur = 27;
- kMainDlgFlipHoriz = 29;
- kMainDlgFlipVert = 30;
- kMainDlgSlideL = 34;
- kMainDlgSlideR = 35;
- kMainDlgSlideT = 36;
- kMainDlgSlideB = 37;
- kMainDlgApertureIn = 32;
- kMainDlgApertureOut = 38;
- kMainDlgTechDemo = 39;
- { The CopyBits Technical Demo dialog ID. }
- kTechDemoDlgID = 130;
- { Item numbers in the Technical Demo dialog. }
- kTechDemoSourceFirst = 10;
- kTechDemoSourceLast = 14;
- kTechDemoMaskFirst = 15;
- kTechDemoMaskLast = 18;
- kTechDemoModeFirst = 21;
- kTechDemoModeLast = 36;
- kTechDemoDither = 37;
- kTechDemoHilite = 38;
- kTechDemoOpColorFirst = 42;
- kTechDemoOpColorLast = 46;
- kTechDemoDestPict = 9;
- kTechDemoCopyBits = 49;
- kTechDemoCopyMask = 50;
- kTechDemoDone = 51;
- kTechDemoSourcePict1 = 1;
- kTechDemoSourcePict2 = 2;
- kTechDemoSourcePict3 = 3;
- kTechDemoSourcePict4 = 4;
- kTechDemoSourcePict5 = 5;
- kTechDemoMaskPict1 = 6;
- kTechDemoMaskPict2 = 7;
- kTechDemoMaskPict3 = 8;
- kTechDemoMaskNone = 53;
- kTechDemoOpColorPict = 40;
- kTechDemoErase = 54;
- kTechDemoCopyDeepMask = 55;
- kTechDemoMaskRPict1 = 56;
- kTechDemoMaskRPict2 = 57;
- kTechDemoMaskRPict3 = 58;
- kTechDemoMaskRNone = 60;
- kTechDemoMaskRFirst = 61;
- kTechDemoMaskRLast = 64;
- { Error messages. ('STR ' resource IDs). }
- kSys7Required = 128;
- kMemoryOut = 129;
- kGWorldErr = 130;
- kNotYetImplemented = 131;
- kMissingResource = 132;
- { The generic error alert ID. }
- kAlertDialogID = 129;
- { Item numbers in the generic alert dialog. }
- kAlertOKButton = 1;
- { Codes sent to the Slide routine to indicate which }
- { way to slide the new picture in (from). }
- kLeft = 1;
- kRight = 2;
- kTop = 3;
- kBottom = 4;
- { Codes sent to the Aperture routine to indicate which }
- { way to do the effect. }
- kIn = 1;
- kOut = 2;
- { Easy way to access colors in the global colors array. }
- kWhite = 0;
- kLtGray = 1;
- kGray = 2;
- kDkGray = 3;
- kBlack = 4;
-
- Var
- colors: array[0..4] of RGBColor; { white, black, and 3 grays }
- mainDlg,aDlg: DialogPtr;
- pict1Rect: rect;
- pict2Rect: rect;
- destRect: rect;
- savedPen: PenState;
- itemHit: integer;
- savedFore: RGBColor;
- savedBack: RGBColor;
- fadeSpeed: integer;
- myErr: OSErr;
- pict1GRect: rect;
- pict2GRect: rect;
- pict1GWorld: GWorldPtr;
- pict2GWorld: GWorldPtr;
- myEvent: EventRecord;
- aPict: PicHandle;
- myPictInfo: PictInfo;
- aDevice: GDHandle;
- dlgUpLeftCorner: point;
- err: OSErr;
- tempRect: rect;
- mouseLoc: point;
-
- Function WinBitMap(w: univ ptr): bitmap;
-
- begin
- WinBitMap := GrafPtr(w)^.portBits;
- end;
-
- { FadeToImage takes the source image and does a smooth fade in
- { the destination window and rect from the image that is currently
- { there to the source image. This is done using CopyBits with
- { the "blend" transfer mode.}
- Procedure FadeToImage(srcImage: GWorldPtr; srcRect: Rect;
- destWin: WindowPtr; destRect: Rect; fadeSpeed: integer);
-
- Var
- savedPort: CGrafPtr;
- savedDevice: GDHandle;
- savedFore,
- savedBack: RGBColor;
- savedPen: PenState;
- grayColor: RGBColor;
- speed: real;
- lastColor: integer;
-
- begin
- { Make sure speed is within our limits and set it appropriately.
- { We want to end up with a range of 1.2 to 3.2 from the original
- { 0 to 20 range.}
- if fadeSpeed < 1 then
- speed := 1.2
- else if fadeSpeed > 20 then
- speed := 3.2
- else
- begin
- speed := fadeSpeed;
- speed := 1.2 + (speed/10);
- end;
- { Save the current port and device }
- GetGWorld(savedPort, savedDevice);
- { Set the port to the destination window and save its
- { pen state and fore/background color values. }
- SetGWorld(CGrafPtr(destWin), NIL);
- GetPenState(savedPen);
- GetForeColor(savedFore);
- GetBackColor(savedBack);
- { Make sure the port's fore and background colors are set
- { correctly for CopyBits to work correctly.}
- RGBForeColor(colors[kBlack]);
- RGBBackColor(colors[kWhite]);
- { Lock the pixels in the source image. This is required
- { when copying from a GWorld. }
- if not LockPixels(GetGWorldPixMap(srcImage)) then
- ;
- { Set the beginning blend weight. This will be multiplied by
- { speed before being used the first time. }
- grayColor.blue := $0F00;
- grayColor.green := $0F00;
- grayColor.red := $0F00;
- lastColor := 0;
- { Loop and copy the source image to the destination
- { blending more and more of the source image in by using
- { a lighter and lighter "blend weight" (set by the OpColor
- { function).}
- while (grayColor.blue <> $FFFF) do
- begin
- { Lighten the blend weight color. }
- grayColor.blue := trunc(grayColor.blue * speed);
- { Make sure the number didn't roll over. }
- if (grayColor.blue < lastColor) then
- grayColor.blue := $FFFF;
- grayColor.red := grayColor.blue;
- grayColor.green := grayColor.blue;
- { Remember the number for next time. }
- lastColor := grayColor.blue;
- { Set the new blend weight. }
- OpColor(grayColor);
- { copy the image }
- CopyBits(WinBitMap(srcImage), WinBitMap(destWin),
- srcRect, destRect, blend, NIL);
- end;
- { Finally, just copy the source image to the destination
- { window unchanged to make sure the transformation is
- { complete. }
- CopyBits(WinBitMap(srcImage), WinBitMap(destWin),
- srcRect, destRect, srcCopy, NIL);
- { Reset the blend weight to black.
- { This is the "normal" weight.}
- OpColor(colors[kBlack]);
- { Unlock the pixels in the source image. }
- UnlockPixels(GetGWorldPixMap(srcImage));
- { Restore the destination window's properties. }
- SetPenState(savedPen);
- RGBForeColor(savedFore);
- RGBBackColor(savedBack);
- { Restore the current port and device. }
- SetGWorld(savedPort, savedDevice);
- end;
-
- { FadeToBlack1 creates a black rectangle in an offscreen GWorld that
- { is the same size as the destination area. It then calls FadetoImage
- { to fade this into the destination thus fading it to black.
- }
- Procedure FadeToBlack1(destWin: WindowPtr; destRect: Rect; fadeSpeed: integer);
-
- Var
- savedPort: CGrafPtr;
- savedDevice: GDHandle;
- offscreenWorld: GWorldPtr;
- myErr: OSErr;
-
- begin
- { Save the current port/device. This should be used instead
- { of GetPort. Though savedPort is defined as a CGrafPtr,
- { the routine may return a GrafPtr or pointer to a GWorld
- { instead (GWorldPtr).}
- GetGWorld(savedPort,savedDevice);
- {
- { Create an offscreen GWorld with the same depth and size as the
- { destination window/rectangle. Even though the rectangle is all the
- { same shade, we make it the same size as the destination because
- { CopyBits works much faster when it doesn't have to resize the
- { image. The parameters are as follows:
- { &offscreenWorld ptr to new graphics world
- { 0 bit depth same as graphics device of dest rect
- { destRect bounds rectangle of my GWorld
- { NIL handle to a color table record - NIL means
- { use the default record for that depth
- { NIL handle to a graphics device record - we aren't
- { creating a new graphics device
- { 0L no flags
- }
- myErr := NewGWorld(offscreenWorld, 0, destRect, NIL, NIL, 0);
- { Make sure the GWorld was created }
- if myErr <> NoErr then
- begin
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- {
- { Get the GWorld's pixel map handle and lock the pixels while we're
- { drawing to the GWorld. We have to do this because a GWorld actually
- { holds its pixel map in a handle rather than a pointer. LockPixels
- { makes sure the pixel map doesn't move. You should lock a GWorld's
- { pixels before drawing to or copying from the GWorld (and unlock
- { them afterward).
- }
- if not LockPixels(GetGWorldPixMap(offscreenWorld)) then
- ;
- SetGWorld(offscreenWorld, NIL); { Make the GWorld the current port. }
- PaintRect(offscreenWorld^.portRect); { Paint the offscreen GWorld all black. }
- SetGWorld(savedPort, savedDevice); { Restore the saved port/device. }
- UnlockPixels(GetGWorldPixMap(offscreenWorld)); { Unlock the pixels of the GWorld.}
- { Call FadeToImage to fade the black rectangle to the destination. }
- FadeToImage(offscreenWorld, offscreenWorld^.portRect,
- destWin, destRect, fadeSpeed);
- DisposeGWorld(offscreenWorld); { Now get rid of the black GWorld. }
- end;
-
- { FadeToBlack2 uses CopyBits and an offscreen graphics world to
- { fade an area (specified by destRect) in a window (specified
- { by destWin) to black. It does this by creating an offscreen
- { graphics world, painting the GWorld gray, then repeatedly
- { copying the gray rectangle to the destination area using the
- { subPin transfer method of CopyBits. This causes the destination
- { to grow darker and darker.
- }
- Procedure FadeToBlack2(destWin: WindowPtr; destRect: Rect; fadeSpeed: integer);
-
- Var
- savedPort: CGrafPtr;
- savedDevice: GDHandle;
- offscreenWorld: GWorldPtr;
- offscreenRect: Rect;
- myErr: OSErr;
- savedPen: PenState;
- savedFore: RGBColor;
- savedBack: RGBColor;
- repetitions: longint;
- grayColor: RGBColor;
- maxValue: longint;
-
- begin
- maxValue := $0FFFF;
- { Save the current port/device. This should be used instead
- { of GetPort. Though savedPort is defined as a CGrafPtr,
- { the routine may return a GrafPtr or pointer to a GWorld
- { instead (GWorldPtr).}
- GetGWorld(savedPort,savedDevice);
- { Set the current port to the destination window }
- SetGWorld(CGrafPtr(destWin), NIL);
- { Save the pen state and color info of the destination window }
- GetPenState(savedPen);
- GetForeColor(savedFore);
- GetBackColor(savedBack);
- { Make sure the foreground color of the destination window }
- { is black and the background color is white. }
- RGBForeColor(colors[kBlack]);
- RGBBackColor(colors[kWhite]);
- { Convert the destination rectangle into global coordinates }
- offscreenRect := destRect;
- LocalToGlobal(offscreenRect.topLeft);
- LocalToGlobal(offscreenRect.botRight);
- { Make the offscreen rectangle smaller. It doesn't matter since it's }
- { all the same color and it'll use up less memory.}
- offscreenRect.right := offscreenRect.left + 2;
- offscreenRect.bottom := offscreenRect.top + 2;
- { Create an offscreen GWorld with the same depth as the
- { destination window/rectangle. The parameters are as follows:
- { &offscreenWorld ptr to new graphics world
- { 0 bit depth same as graphics device of dest rect
- { &offscreenRect bounds rectangle of my GWorld
- { NIL handle to a color table record - NIL means
- { use the default record for that depth
- { NIL handle to a graphics device record - we aren't
- { creating a new graphics device
- { 0L no flags}
- myErr := NewGWorld(offscreenWorld, 0, offscreenRect, NIL, NIL, 0);
- { Make sure the GWorld was created }
- if myErr <> NoErr then
- begin
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- { Make the GWorld the current port }
- SetGWorld(offscreenWorld, NIL);
- { Get the GWorld's pixel map handle and lock the pixels while we're
- { drawing in the GWorld. We have to do this because a GWorld actually
- { holds its pixel map in a handle rather than a pointer. LockPixels
- { makes sure the pixel map doesn't move. You should lock a GWorld's
- { pixels before drawing to or copying from the GWorld (and unlock
- { them afterward).}
- if not LockPixels(GetGWorldPixMap(offscreenWorld)) then
- ;
- { The speed of the fade determines what shade of gray we'll paint
- { the offscreen GWorld. fadeSpeed can range from 0 to 20 with 20
- { being the fastest.}
- if fadeSpeed <= 0 then
- fadeSpeed := 1; { make sure speed is not zero }
- if fadeSpeed > 20 then
- fadeSpeed := 20; { make sure not over 20 }
- grayColor.blue := (fadeSpeed * 625) + 8000;
- grayColor.red := grayColor.blue;
- grayColor.green := grayColor.blue;
- RGBForeColor(grayColor);
- repetitions := maxValue div grayColor.blue;
- { Paint it all gray }
- PaintRect(offscreenWorld^.portRect);
- { Make the destination window the current port }
- SetGWorld(CGrafPtr(destWin), NIL);
- { Loop and use CopyBits to copy the gray rectangle into the
- { destination window/rect using the subPin transfer method
- { so that the picture gets darker and darker. }
- while repetitions > 0 do
- begin
- CopyBits(WinBitMap(offscreenWorld), WinBitMap(destWin),
- offscreenWorld^.portRect, destRect, subPin, NIL);
- dec(repetitions);
- end;
- { Make the GWorld the current port }
- SetGWorld(offscreenWorld, NIL);
- { Now we'll do a fast fade just to make sure everything went completely
- { to black.}
- grayColor.blue := 20500;
- grayColor.red := grayColor.blue;
- grayColor.green := grayColor.blue;
- RGBForeColor(grayColor);
- repetitions := maxValue div grayColor.blue + 1;
- { Paint it all gray }
- PaintRect(offscreenWorld^.portRect);
- { Make the destination window the current port }
- SetGWorld(CGrafPtr(destWin), NIL);
- { Loop and use CopyBits to copy the gray rectangle into the
- { destination window/rect using the subPin transfer method
- { so that the picture gets darker and darker.}
- while repetitions > 0 do
- begin
- CopyBits(WinBitMap(offscreenWorld), WinBitMap(destWin),
- offscreenWorld^.portRect, destRect, subPin, NIL);
- dec(repetitions);
- end;
- { Unlock the pixels again. }
- UnlockPixels(GetGWorldPixMap(offscreenWorld));
- { Paint the destination rectangle all black. }
- PaintRect(destRect);
- { Restore the saved port/device }
- SetGWorld(savedPort, savedDevice);
- { Restore the pen state and color info of the destination window }
- SetPenState(savedPen);
- RGBForeColor(savedFore);
- RGBBackColor(savedBack);
- { Dispose of the GWorld }
- DisposeGWorld(offscreenWorld);
- end;
-
- { FadeToBlack3 uses CopyBits and an offscreen graphics world to
- { fade an area (specified by destRect) in a window (specified
- { by destWin) to black. It does this by creating an offscreen
- { graphics world, and repeatedly copying darker and darker
- { shades of gray into the destination using the adMin transfer
- { method of CopyBits. This method compares the pixels in the
- { source (gray) and destination images and replaces the pixel
- { in the destination if the source is darker (closer to zero).
- { This has the effect of making the destination darker and
- { darker starting with the lighter colors and ending with the
- { darker colors and eventually blacking the destination out.
- }
- Procedure FadeToBlack3(destWin: WindowPtr; destRect: Rect; fadeSpeed: integer);
-
- Var
- savedPort: CGrafPtr;
- savedDevice: GDHandle;
- offscreenWorld: GWorldPtr;
- offscreenRect: rect;
- myErr: OSerr;
- savedFore: RGBColor;
- savedBack: RGBColor;
- grayColor: RGBColor;
- colorStep: longint;
- grayStep: longint;
- speed: integer;
-
- begin
- { Save the current port/device. This should be used instead
- { of GetPort. Though savedPort is defined as a CGrafPtr,
- { the routine may return a GrafPtr or pointer to a GWorld
- { instead (GWorldPtr).}
- GetGWorld(savedPort, savedDevice);
- { Set the current port to the destination window.}
- SetGWorld(CGrafPtr(destWin), NIL);
- { Save the color info of the destination window.}
- GetForeColor(savedFore);
- GetBackColor(savedBack);
- { Make sure the foreground color of the destination window
- { is black and the background color is white.}
- RGBForeColor(colors[kBlack]);
- RGBBackColor(colors[kWhite]);
- { Convert the destination rectangle into global coordinates.}
- offscreenRect := destRect;
- LocalToGlobal(offscreenRect.topleft);
- LocalToGlobal(offscreenRect.botRight);
- {LocalToGlobal(* (Point*) &(r.top));
- LocalToGlobal(* (Point*) &(r.bottom));}
- myErr := NewGWorld(offscreenWorld, 0, offscreenRect, NIL, NIL, 0);
- { Make sure the GWorld was created }
- if myErr <> NoErr then
- begin
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- { Get the GWorld's pixel map handle and lock the pixels while we're
- { drawing to the GWorld. We have to do this because a GWorld actually
- { holds its pixel map in a handle rather than a pointer. LockPixels
- { makes sure the pixel map doesn't move. You should lock a GWorld's
- { pixels before drawing to or copying from the GWorld (and unlock
- { them afterward).}
- if not LockPixels(GetGWorldPixMap(offscreenWorld)) then
- ;
- { Determine the number to subtract from the gray shade every time we
- { loop. This is determined by the fadeSpeed parameter.}
- if fadeSpeed < 0 then
- speed := 0
- else if fadeSpeed > 20 then
- speed := 20
- else
- speed := fadeSpeed;
- colorStep := trunc($0FFFF / (21 - fadeSpeed)) div 2;
- { Our gray color just starts out as white. }
- grayColor := colors[kWhite];
- grayStep := $0FFFF;
- { Loop until the gray color is black. }
- while (grayStep > 0) do
- begin
- { Make the GWorld the current port. }
- SetGWorld(offscreenWorld, NIL);
- { Subtract the color step value from the gray value and
- { paint the offscreen GWorld.}
- if (grayStep > colorStep) then
- grayStep := grayStep - colorStep
- else
- grayStep := 0;
- grayColor.blue := grayStep;
- grayColor.green := grayColor.blue;
- grayColor.red := grayColor.blue;
- RGBForeColor(grayColor);
- PaintRect(offscreenWorld^.portRect);
- { Make the destination window the current port.}
- SetGWorld(CGrafPtr(destWin), NIL);
- { Use CopyBits with the adMin transfer mode to copy the
- { gray rectangle to the destination window/area.}
- CopyBits(WinBitMap(offscreenWorld), WinBitMap(destWin),
- offscreenWorld^.portRect, destRect, adMin, NIL);
- end;
- { Set the current port to the destination window. }
- SetGWorld(CGrafPtr(destWin), NIL);
- { Restore the color info of the destination window. }
- RGBForeColor(savedFore);
- RGBBackColor(savedBack);
- { Restore the saved port/device. }
- SetGWorld(savedPort, savedDevice);
- { Unlock the pixels of the GWorld and dispose of it. }
- UnlockPixels(GetGWorldPixMap(offscreenWorld));
- DisposeGWorld(offscreenWorld);
- end;
-
- { Pixelize makes a picture "blockier" in several steps.
- { It first copies the original picture from the destination
- { area, then repeatedly copies the original picture
- { into areas smaller than the size of the previous one,
- { using CopyBits to scale the picture back up into the
- { destination window at the original size.
- {
- { The srcWin/srcRect and destWin/destRect may be the same
- { window/area to pixelize, but not to depixelize.
- { When depixelizing, srcWin will usually be a GWorldPtr
- { containing an image the same size as the destination area.
- }
- Procedure Pixelize(srcWin: WindowPtr; srcRect: Rect;
- destWin: WindowPtr; destRect: Rect; speed: integer; pixelizing: boolean);
-
- Var
- srcImage: GWorldPtr;
- intermedImage: GWorldPtr;
- intermedRect: Rect;
- savedPort: CGrafPtr;
- savedDevice: GDHandle;
- myErr: OSErr;
- theSpeed: real;
- done: boolean;
-
- begin
- { Make sure speed is within our limits and set it appropriately.
- { We want to end up with a range of 1.1 to 2.1 from the original
- { 0 to 20 range.}
- if (speed < 1) then
- theSpeed := 1.1
- else if (speed > 20) then
- theSpeed := 2.1
- else
- begin
- theSpeed := speed;
- theSpeed := 1.1 + (theSpeed/20);
- end;
- { Save the original port and device. }
- GetGWorld(savedPort, savedDevice);
- { Create an offscreen GWorld with the same depth as the
- { destination window/rectangle. The parameters are as follows:
- { &srcImage ptr to new graphics world
- { 0 bit depth same as graphics device of dest rect
- { destRect bounds rectangle of my GWorld
- { NIL handle to a color table record - NIL means
- { use the default record for that depth
- { NIL handle to a graphics device record - we aren't
- { creating a new graphics device
- { 0L no flags }
- myErr := NewGWorld(srcImage, 0, destRect, NIL, NIL, 0);
- { Make sure the GWorld was created }
- if myErr <> NoErr then
- begin
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- { Also create an intermediate GWorld used in the scaling/copying. }
- myErr := NewGWorld(intermedImage, 0, destRect, NIL, NIL, 0);
- { Make sure the GWorld was created }
- if myErr <> NoErr then
- begin
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- { Copy the source image into the GWorld. }
- SetGWorld(srcImage, NIL);
- CopyBits(WinBitMap(srcWin), WinBitMap(srcImage),
- srcRect, srcImage^.portRect, srcCopy, NIL);
- { Lock the pixels of the source and intermediate GWorlds
- { since we'll be copying from them. }
- if not LockPixels(GetGWorldPixMap(srcImage)) then
- ;
- if not LockPixels(GetGWorldPixMap(intermedImage)) then
- ;
- { We need a beginning intermediate image size. }
- if pixelizing then
- intermedRect := intermedImage^.portRect
- else
- begin
- intermedRect := intermedImage^.portRect;
- intermedRect.bottom := intermedRect.bottom div 15;
- intermedRect.right := intermedRect.right div 15;
- end;
- { Loop and copy the image into smaller GWorlds. }
- done := false;
- while not done do
- begin
- { Adjust the intermediate rectangle size and determine if
- { this will be the last time through the loop. }
- if pixelizing then
- begin
- intermedRect.bottom := trunc(intermedRect.bottom / theSpeed);
- intermedRect.right := trunc(intermedRect.right / theSpeed);
- if (intermedRect.bottom < (intermedImage^.portRect.bottom / 10)) then
- done := true;
- end
- else
- begin
- intermedRect.bottom := trunc(intermedRect.bottom * theSpeed);
- intermedRect.right := trunc(intermedRect.right * theSpeed);
- if ((intermedRect.bottom > intermedImage^.portRect.bottom) |
- (intermedRect.right > intermedImage^.portRect.right)) then
- begin
- intermedRect := intermedImage^.portRect;
- done := true;
- end;
- end;
- { Copy the original image into the intermediate GWorld. }
- SetGWorld(CGrafPtr(intermedImage), NIL);
- CopyBits(WinBitMap(srcImage), WinBitMap(intermedImage),
- srcImage^.portRect, intermedRect, srcCopy, NIL);
- { Copy the intermediate GWorld to the destination. }
- SetGWorld(CGrafPtr(destWin), NIL);
- CopyBits(WinBitMap(intermedImage), WinBitMap(destWin),
- intermedRect, destRect, srcCopy, NIL);
- end;
- { Unlock everyone's pixels again. }
- UnlockPixels(GetGWorldPixMap(srcImage));
- UnlockPixels(GetGWorldPixMap(intermedImage));
- { Restore the original port and device. }
- SetGWorld(savedPort, savedDevice);
- { Destroy the GWorld holding the original image and the
- { intermediate GWorld. }
- DisposeGWorld(srcImage);
- DisposeGWorld(intermedImage);
- end;
-
- { FlickerAnimate animates a colored circle floating over
- { a picture at the mouse location. It draws directly to
- { the screen resulting in a circle that the background
- { occasionally "flickers" through. Drawing will occur in
- { the current port.
- }
- Procedure FlickerAnimate(srcPict: GWorldPtr; destRect: Rect);
-
- Var
- mouseLoc: Point;
- mouseRect: Rect;
- savedFore: RGBColor;
- savedBack: RGBColor;
- savedClip: RgnHandle;
- redColor: RGBColor;
- ignore: longint;
-
- begin
- { Make the color to draw the circle with. }
- redColor.blue := 0;
- redColor.green := 0;
- redColor.red := $0FFFF;
- { Save fore and background colors and make them
- { fore-black and back-white. }
- GetForeColor(savedFore);
- GetBackColor(savedBack);
- RGBForeColor(colors[kBlack]);
- RGBBackColor(colors[kWhite]);
- { Save the clipping region. }
- savedClip := NewRgn;
- GetClip(savedClip);
- { Set the clipping region to just cover the picture. }
- ClipRect(destRect);
- { Lock the pixel map of the src GWorld while copying from it. }
- if not LockPixels(GetGWorldPixMap(srcPict)) then
- ;
- { Loop and draw the picture and circle repeatedly. }
- repeat
- { Get a mouse location. }
- GetMouse(mouseLoc);
- { Make a square around the mouse location to draw
- { the circle in. }
- mouseRect.left := mouseLoc.h;
- mouseRect.right := mouseLoc.h;
- mouseRect.top := mouseLoc.v;
- mouseRect.bottom := mouseLoc.v;
- InsetRect(mouseRect, -20, -20);
- { Copy the picture to the window. }
- CopyBits(WinBitMap(srcPict), WinBitMap(FrontWindow),
- srcPict^.portRect, destRect, srcCopy, NIL);
- { Draw the circle at the mouse location. }
- RGBForeColor(redColor);
- PaintOval(mouseRect);
- RGBForeColor(colors[kBlack]);
- { Delay for a fraction of a second here. If we
- { don't, the flickering is really, really bad. }
- Delay(2, ignore);
- until not PtInRect(mouseLoc, destRect);
- { Draw the picture one more time to make sure the
- { circle is erased. }
- CopyBits(WinBitMap(srcPict), WinBitMap(FrontWindow()),
- srcPict^.portRect, destRect, srcCopy, NIL);
- { Unlock the GWorld's pixel map. }
- UnlockPixels(GetGWorldPixMap(srcPict));
- { Restore the clipping region. }
- SetClip(savedClip);
- { Restore the saved fore and background colors. }
- RGBForeColor(savedFore);
- RGBBackColor(savedBack);
- end;
-
- { SmoothAnimate animates a colored circle floating over
- { a picture at the mouse location. It draws to a GWorld
- { then copies the GWorld to the screen. This results in
- { flicker-free animation where the background never
- { shows through the floating circle.
- }
- Procedure SmoothAnimate(srcPict: GWorldPtr; destRect: rect);
-
- Var
- mouseLoc: Point;
- mouseRect: Rect;
- savedFore: RGBColor;
- savedBack: RGBColor;
- srcPixMap: PixMapHandle;
- midPixMap: PixMapHandle;
- middleMan: GWorldPtr;
- thisWindow: CGrafPtr;
- thisDevice: GDHandle;
- purpleColor: RGBColor;
- myErr: OSErr;
-
- begin
- { Save the current window and device (this is the window
- { we're drawing into.) }
- GetGWorld(thisWindow, thisDevice);
- { Make the color to draw the circle with. }
- purpleColor.blue := $0FFFF;
- purpleColor.red := $0FFFF;
- purpleColor.green := 0;
- { Save fore and background colors and make them
- { fore-black and back-white. }
- GetForeColor(savedFore);
- GetBackColor(savedBack);
- RGBForeColor(colors[kBlack]);
- RGBBackColor(colors[kWhite]);
- myErr := NewGWorld(middleMan, 0, destRect, NIL, NIL, 0);
- { Make sure the GWorld was created }
- if (myErr <> NoErr) | (middleMan = NIL) then
- begin
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- { Lock the pixel map of the src GWorld and the middleMan
- { GWorld while copying from them. }
- srcPixMap := GetGWorldPixMap(srcPict);
- if not LockPixels(srcPixMap) then;
- midPixMap := GetGWorldPixMap(middleMan);
- if not LockPixels(midPixMap) then;
- { Loop and draw the pict and the circle repeatedly. }
- repeat
- { Get a mouse location and translate into coordinates
- { local to the middleMan GWorld. }
- GetMouse(mouseLoc);
- mouseLoc.h := mouseLoc.h - destRect.left;
- mouseLoc.v := mouseLoc.v - destRect.top;
- { Make a square around the mouse location to draw
- { the circle in. }
- mouseRect.left := mouseLoc.h;
- mouseRect.right := mouseLoc.h;
- mouseRect.top := mouseLoc.v;
- mouseRect.bottom := mouseLoc.v;
- InsetRect(mouseRect, -20, -20);
- { Set the current port to middleMan. }
- SetGWorld(CGrafPtr(middleMan), NIL);
- { Copy the picture to the middleMan GWorld. }
- CopyBits(WinBitMap(srcPict), WinBitMap(middleMan),
- srcPict^.portRect, middleMan^.portRect, srcCopy, NIL);
- { Draw the circle at the mouse location. }
- RGBForeColor(purpleColor);
- PaintOval(mouseRect);
- RGBForeColor(colors[kBlack]);
- { Reset the current port to the destination window. }
- SetGWorld(thisWindow, thisDevice);
- { Now copy the middleMan image to the destination
- { window on screen. }
- CopyBits(WinBitMap(middleMan), WinBitMap(thisWindow),
- middleMan^.portRect, destRect, srcCopy, NIL);
- until not PtInRect(mouseLoc, middleMan^.portRect);
- { Draw the picture one more time to make sure the
- { circle is erased. }
- CopyBits(WinBitMap(srcPict), WinBitMap(FrontWindow),
- srcPict^.portRect, destRect, srcCopy, NIL);
- { Unlock the GWorld's and middleMan's pixel maps. }
- UnlockPixels(srcPixMap);
- UnlockPixels(midPixMap);
- { Dispose of the middleMan GWorld. }
- DisposeGWorld(middleMan);
- { Restore the saved fore and background colors. }
- RGBForeColor(savedFore);
- RGBBackColor(savedBack);
- end;
-
- { Blur blurs the destination picture by varying the destination image
- { in an offscreen GWorld slightly and blending the varied images back
- { into the original destination image.
- }
- Procedure Blur(destWin: WindowPtr; destRect: rect);
-
- Var
- savedPort: CGrafPtr;
- savedDevice: GDHandle;
- offscreenWorld: GWorldPtr;
- copyRect: Rect;
- savedFore: RGBColor;
- savedBack: RGBColor;
- grayColor: RGBColor;
- myErr: OSErr;
- x: integer;
- savedClip: RgnHandle;
-
- begin
- { Save the current device and port. }
- GetGWorld(savedPort, savedDevice);
- { Create a GWorld the same size as the destination image
- { with the same depth as the destination window/rectangle.
- { The parameters are as follows:
- { &offscreenWorld ptr to new graphics world
- { 0 bit depth same as graphics device of dest rect
- { destRect bounds rectangle of my GWorld
- { NIL handle to a color table record - NIL means
- { use the default record for that depth
- { NIL handle to a graphics device record - we aren't
- { creating a new graphics device
- { 0 no flags }
- myErr := NewGWorld(offscreenWorld, 0, destRect, NIL, NIL, 0);
- { Make sure the GWorld was created }
- if myErr <> NoErr then
- begin
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- { Make the GWorld the current port. }
- SetGWorld(CGrafPtr(offscreenWorld), NIL);
- { Copy the destination image into the GWorld. }
- CopyBits(WinBitMap(destWin), WinBitMap(offscreenWorld),
- destRect, offscreenWorld^.portRect, srcCopy, NIL);
- { Make the destination window the current port. }
- SetGWorld(CGrafPtr(destWin), NIL);
- { Save the destination window's fore/background colors. }
- GetBackColor(savedBack);
- GetForeColor(savedFore);
- { Make sure the destination window's fore/background colors
- { are black/white. }
- RGBForeColor(colors[kBlack]);
- RGBBackColor(colors[kWhite]);
- { Save the destination window's clip region and set it to
- { the destination rectangle. }
- savedClip := NewRgn;
- GetClip(savedClip);
- ClipRect(destRect);
- { Set the OpColor for blending. }
- grayColor.red := $4000;
- grayColor.green := $4000;
- grayColor.blue := $4000;
- OpColor(grayColor);
- { Lock the GWorld's pixels while we copy from it. }
- if not LockPixels(GetGWorldPixMap(offscreenWorld)) then;
- { Blend the GWorld image back into the destination image in
- { a circular pattern. }
- for x := 1 to 8 do
- begin
- copyRect := destRect;
- case x of
- 1: OffsetRect(copyRect, -2, 0);
- 2: OffsetRect(copyRect, -1, -1);
- 3: OffsetRect(copyRect, 0, -2);
- 4: OffsetRect(copyRect, 1, -1);
- 5: OffsetRect(copyRect, 2, 0);
- 6: OffsetRect(copyRect, 1, 1);
- 7: OffsetRect(copyRect, 0, 2);
- 8: OffsetRect(copyRect, -1, 1);
- {CASE} end;
- CopyBits(WinBitMap(offscreenWorld), WinBitMap(destWin),
- offscreenWorld^.portRect, copyRect, blend, NIL);
- end;
- { Unlock the GWorld's pixels. }
- UnlockPixels(GetGWorldPixMap(offscreenWorld));
- { Reset OpColor to black. }
- OpColor(colors[kBlack]);
- { Get rid of the GWorld. }
- DisposeGWorld(offscreenWorld);
- { Restore the destination window's fore/background colors.}
- RGBForeColor(savedFore);
- RGBBackColor(savedBack);
- { Restore the destination window's clipping region. }
- SetClip(savedClip);
- DisposeRgn(savedClip);
- { Restore the saved port and device. }
- SetGWorld(savedPort, savedDevice);
- end;
-
- { FlipHorizontal copies the image in the window and rectangle
- { specified and draws it back out reversed horizontally.
- }
- Procedure FlipHorizontal(destWin: WindowPtr; destRect: Rect);
-
- Var
- savedPort: CGrafPtr;
- savedDevice: GDHandle;
- offscreenWorld: GWorldPtr;
- savedFore: RGBColor;
- savedBack: RGBColor;
- myErr: OSErr;
- x: integer;
- copyFrom: Rect;
- copyTo: Rect;
-
- begin
- { Save the current device and port. }
- GetGWorld(savedPort, savedDevice);
- myErr := NewGWorld(offscreenWorld, 0, destRect, NIL, NIL, 0);
- { Make sure the GWorld was created }
- if myErr <> NoErr then
- begin
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- { Make the GWorld the current port. }
- SetGWorld(CGrafPtr(offscreenWorld), NIL);
- { Set up the copy from and to rectangles. }
- copyFrom := destRect;
- copyFrom.right := copyFrom.left + 1;
- copyTo := offscreenWorld^.portRect;
- copyTo.left := copyTo.right - 1;
- { Copy the destination image into the GWorld column by column
- { reversing it as we go. }
- for x := 1 to (destWin^.portRect.right - destWin^.portRect.left) do
- begin
- CopyBits(WinBitMap(destWin), WinBitMap(offscreenWorld),
- copyFrom, copyTo, srcCopy, NIL);
- OffsetRect(copyFrom, 1, 0);
- OffsetRect(copyTo, -1, 0);
- end;
- { Make the destination window the current port. }
- SetGWorld(CGrafPtr(destWin), NIL);
- { Save the destination window's fore/background colors. }
- GetBackColor(savedBack);
- GetForeColor(savedFore);
- { Make sure the destination window's fore/background colors
- { are black/white. }
- RGBForeColor(colors[kBlack]);
- RGBBackColor(colors[kWhite]);
- { Lock the GWorld's pixels while we copy from it. }
- if not LockPixels(GetGWorldPixMap(offscreenWorld)) then;
- { Now copy the reversed image back to the destination window. }
- CopyBits(WinBitMap(offscreenWorld), WinBitMap(destWin),
- offscreenWorld^.portRect, destRect, srcCopy, NIL);
- { Unlock the GWorld's pixels now. }
- UnlockPixels(GetGWorldPixMap(offscreenWorld));
- { Get rid of the GWorld. }
- DisposeGWorld(offscreenWorld);
- { Restore the destination window's fore/background colors. }
- RGBForeColor(savedFore);
- RGBBackColor(savedBack);
- { Restore the saved port and device. }
- SetGWorld(savedPort, savedDevice);
- end;
-
- { FlipVertical copies the image in the window and rectangle
- { specified and draws it back out reversed vertically.
- }
- Procedure FlipVertical(destWin: WindowPtr; destRect: rect);
-
- Var
- savedPort: CGrafPtr;
- savedDevice: GDHandle;
- offscreenWorld: GWorldPtr;
- savedFore: RGBColor;
- savedBack: RGBColor;
- myErr: OSErr;
- x: integer;
- copyFrom: rect;
- copyTo: rect;
-
- begin
- { Save the current device and port. }
- GetGWorld(savedPort, savedDevice);
- myErr := NewGWorld(offscreenWorld, 0, destRect, NIL, NIL, 0);
- { Make sure the GWorld was created }
- if myErr <> NoErr then
- begin
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- { Make the GWorld the current port. }
- SetGWorld(CGrafPtr(offscreenWorld), NIL);
- { Set up the copy from and to rectangles. }
- copyFrom := destRect;
- copyFrom.bottom := copyFrom.top + 1;
- copyTo := offscreenWorld^.portRect;
- copyTo.top := copyTo.bottom - 1;
- { Copy the destination image into the GWorld row by row
- { reversing it as we go. }
- for x := 1 to (destWin^.portRect.bottom - destWin^.portRect.top) do
- begin
- CopyBits(WinBitMap(destWin), WinBitMap(offscreenWorld),
- copyFrom, copyTo, srcCopy, NIL);
- OffsetRect(copyFrom, 0, 1);
- OffsetRect(copyTo, 0, -1);
- end;
- { Make the destination window the current port. }
- SetGWorld(CGrafPtr(destWin), NIL);
- { Save the destination window's fore/background colors. }
- GetBackColor(savedBack);
- GetForeColor(savedFore);
- { Make sure the destination window's fore/background colors
- { are black/white. }
- RGBForeColor(colors[kBlack]);
- RGBBackColor(colors[kWhite]);
- { Lock the GWorld's pixels while we copy from it. }
- if not LockPixels(GetGWorldPixMap(offscreenWorld)) then;
- { Now copy the reversed image back to the destination window. }
- CopyBits(WinBitMap(offscreenWorld), WinBitMap(destWin),
- offscreenWorld^.portRect, destRect, srcCopy, NIL);
- { Unlock the GWorld's pixels now. }
- UnlockPixels(GetGWorldPixMap(offscreenWorld));
- { Get rid of the GWorld. }
- DisposeGWorld(offscreenWorld);
- { Restore the destination window's fore/background colors. }
- RGBForeColor(savedFore);
- RGBBackColor(savedBack);
- { Restore the saved port and device. }
- SetGWorld(savedPort, savedDevice);
- end;
-
- { Slide slides the source image onto the destination from the
- { direction specified in whichWay.
- }
- Procedure Slide(srcWin: WindowPtr; srcRect: Rect;
- destWin: WindowPtr; destRect: Rect; speed,whichWay: integer);
-
- Var
- savedFore: RGBColor;
- savedBack: RGBColor;
- savedPort: CGrafPtr;
- savedDevice: GDHandle;
- x,speedToUse: integer;
- pixelsPerLoop: integer;
- pixelsToMove: integer;
- savedClip: RgnHandle;
- drawDest: Rect;
- hDelta, vDelta: integer;
- iterations: integer;
- delayPerLoop: longint;
- ignore: longint;
-
- begin
- { Make sure the speed is within acceptable range. Normally
- { zero is the slowest speed, but we're changing that to 1
- { for this routine. }
- if (speed <= 0) then
- speedToUse := 1
- else if (speed > 20) then
- speedToUse := 20
- else
- speedToUse := speed;
- { Determine how much to delay each loop based on the size
- { of the destination. }
- x := (destRect.right - destRect.left);
- if (x < 200) then
- delayPerLoop := 5
- else if (x < 400) then
- delayPerLoop := 4
- else if (x < 600) then
- delayPerLoop := 3
- else if (x < 800) then
- delayPerLoop := 2
- else if (x < 1000) then
- delayPerLoop := 1
- else
- delayPerLoop := 0;
- { If the destination is not the same size as the source,
- { cut the delay in half to compensate for sizing the picture.
- { I could, of course just copy the source into a GWorld that
- { is the same size as the destination and the sizing would only
- { take place once, but that would also require much more
- { memory than the way I'm doing it now (just copying/sizing
- { each time). }
- if ((destRect.right - destRect.left) <> (srcRect.right - srcRect.left)) |
- ((destRect.bottom - destRect.top) <> (srcRect.bottom - srcRect.top)) then
- delayPerLoop := delayPerLoop div 2;
- { Determine how many pixels the source will have to move to
- { completely cover the destination. This depends on the
- { direction that we're moving. }
- if (whichWay = kLeft) | (whichWay = kRight) then
- pixelsToMove := destRect.right - destRect.left
- else
- pixelsToMove := destRect.bottom - destRect.top;
- { Determine how many pixels to move the source over onto the
- { destination each time through the loop based on the speed
- { parameter. }
- pixelsPerLoop := speedToUse * 2;
- { Save the current port and set it to the destination window. }
- GetGWorld(savedPort, savedDevice);
- SetGWorld(CGrafPtr(destWin), NIL);
- { Save the dest window's colors and set them to black/white. }
- GetForeColor(savedFore);
- RGBForeColor(colors[kBlack]);
- GetBackColor(savedBack);
- RGBBackColor(colors[kWhite]);
- { Save the destination window's clipping region and clip
- { to the destination rectangle. }
- savedClip := NewRgn;
- GetClip(savedClip);
- ClipRect(destRect);
- { Determine where the drawing destination rectangle should
- { initially be. At the same time, set the horizontal and
- { vertical deltas for moving the rectangle. }
- drawDest := destRect;
- hDelta := 0;
- vDelta := 0;
- case whichWay of
- kLeft: begin
- OffsetRect(drawDest, -pixelsToMove, 0);
- hDelta := pixelsPerLoop;
- end;
- kRight: begin
- OffsetRect(drawDest, pixelsToMove, 0);
- hDelta := -pixelsPerLoop;
- end;
- kTop: begin
- OffsetRect(drawDest, 0, -pixelsToMove);
- vDelta := pixelsPerLoop;
- end;
- kBottom:begin
- OffsetRect(drawDest, 0, pixelsToMove);
- vDelta := -pixelsPerLoop;
- end;
- {CASE} end;
- { Loop how many times? }
- iterations := pixelsToMove div pixelsPerLoop;
- { Loop and move the source onto the image. }
- for x := 1 to iterations do
- begin
- { Move the drawing destination rectangle. }
- OffsetRect(drawDest, hDelta, vDelta);
- { Now copy the source image into the drawing
- { destination rectangle we just moved. }
- CopyBits(WinBitMap(srcWin), WinBitMap(destWin),
- srcRect, drawDest, srcCopy, NIL);
- { Delay. }
- if delayPerLoop > 0 then
- Delay(delayPerLoop, ignore);
- end;
- { Copy the image directly into the destination to make
- { sure the move is complete. }
- CopyBits(WinBitMap(srcWin), WinBitMap(destWin),
- srcRect, destRect, srcCopy, NIL);
- { Restore the clipping region. }
- SetClip(savedClip);
- DisposeRgn(savedClip);
- { Restore the dest window's colors. }
- RGBForeColor(savedFore);
- RGBBackColor(savedBack);
- { Restore the saved port. }
- SetGWorld(savedPort, savedDevice);
- end;
-
- { Aperture introduces the source image onto the destination either
- { from the inside of a growing circle, or the outside of a shrinking
- { circle. We use CopyMask along with a circle drawn in a GWorld to
- { accomplish this.
- }
- Procedure Aperture(srcWin: WindowPtr; srcRect: Rect;
- destWin: WindowPtr; destRect: Rect; speed,inOrOut: integer);
-
- Var
- speedToUse: integer;
- savedPort: CGrafPtr;
- savedDevice: GDHandle;
- savedFore: RGBColor;
- savedBack: RGBColor;
- savedClip: RgnHandle;
- maskWorld: GWorldPtr;
- maskRect: Rect;
- sizeDelta: integer;
- destSize: integer;
- x,steps: integer;
-
- begin
- { Save the current port/device. }
- GetGWorld(savedPort, savedDevice);
- { Create a GWorld for the mask image the same size as the
- { destination rectangle. }
- SetGWorld(CGrafPtr(srcWin), NIL);
- if NewGWorld(maskWorld, 0, srcRect, NIL, NIL, 0) <> noErr then
- begin
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end
- else
- if not LockPixels(GetGWorldPixMap(maskWorld)) then;
- { Set the current port to the destination window. }
- SetGWorld(CGrafPtr(destWin), NIL);
- { Save the port's colors and set them to black/white. }
- GetForeColor(savedFore);
- RGBForeColor(colors[kBlack]);
- GetBackColor(savedBack);
- RGBBackColor(colors[kWhite]);
- { Save the port's clip region and clip to the destination rect. }
- savedClip := NewRgn;
- GetClip(savedClip);
- ClipRect(destRect);
- { Make sure the speed is within the correct range. }
- if speed <= 0 then
- speedToUse := 1
- else if speed > 20 then
- speedToUse := 20
- else
- speedToUse := speed;
- { Determine if the destination rectangle is wider than it
- { is tall or the other way around and save the bigger number. }
- if (destRect.right - destRect.left) > (destRect.bottom - destRect.top) then
- destSize := destRect.right - destRect.left
- else
- destSize := destRect.bottom - destRect.top;
- { Make the rectangle that the circle will start in and create
- { a delta value to determine if the circle gets bigger or
- { smaller and by how much each time through the loop.
- { Make sure it's square. }
- maskRect := maskWorld^.portRect;
- if maskRect.bottom - maskRect.top > maskRect.right - maskRect.left then
- begin
- x := maskRect.bottom - maskRect.top;
- InsetRect(maskRect, -(x - (maskRect.right - maskRect.left)) div 2, 0);
- end
- else
- begin
- x := maskRect.right - maskRect.left;
- InsetRect(maskRect, 0, -(x - (maskRect.bottom - maskRect.top)) div 2);
- end;
- if inOrOut = kIn then
- begin
- sizeDelta := destSize div ((21-speedToUse) * 5) + 1;
- InsetRect(maskRect, -trunc(destSize*0.1), -trunc(destSize*0.1));
- steps := trunc((destSize*1.2) / (sizeDelta*2));
- end
- else
- begin
- sizeDelta := -(destSize div ((21-speedToUse) * 5) + 1);
- InsetRect(maskRect, trunc((destSize/2)*0.9), trunc((destSize/2)*0.9));
- steps := -trunc((destSize*1.2)/(sizeDelta*2));
- end;
- { Loop and copy the source image through the mask to the
- { destination making the mask circle bigger or smaller each
- { time. }
- for x := 1 to steps do
- begin
- { Draw the circle in the mask GWorld. }
- SetGWorld(CGrafPtr(maskWorld), NIL);
- EraseRect(maskWorld^.portRect);
- PaintArc(maskRect, 0, 360);
- { If we're going inward, invert the mask GWorld. }
- if inOrOut = kIn then
- InvertRect(maskWorld^.portRect);
- { Copy the source through the mask to the dest. }
- SetGWorld(CGrafPtr(destWin), NIL);
- CopyMask(WinBitMap(srcWin), WinBitMap(maskWorld),
- WinBitMap(destWin), srcRect, maskWorld^.portRect, destRect);
- { Change the size of the circle. }
- InsetRect(maskRect, sizeDelta, sizeDelta);
- end;
- { Copy the source image directly to the destination to make
- { sure it ends correctly.}
- CopyBits(WinBitMap(srcWin), WinBitMap(destWin),
- srcRect, destRect, srcCopy, NIL);
- { Restore the port's colors and clip region. }
- SetClip(savedClip);
- RGBForeColor(savedFore);
- RGBBackColor(savedBack);
- { Restore the saved port. }
- SetGWorld(savedPort, savedDevice);
- { Dispose of the GWorld we used for the mask. }
- UnlockPixels(GetGWorldPixMap(maskWorld));
- DisposeGWorld(maskWorld);
- end;
-
- { DrawMaskRegion draws the contents of each of the three mask regions.
- { The drawing takes place in the rectangle of the item sent as the
- { drawWhere parameter. The whichMask parameter determines what is
- { drawn. When creating the actual mask region to use in the CopyBits
- { operation, we have to make sure and draw the region in the coordinates
- { of the destination image.
- }
- Procedure DrawMaskRegion(win: WindowPtr; drawWhere,whichMask: integer);
-
- Var
- tempRect: rect;
- tempRect2: rect;
- x: integer;
- vMid,hMid: integer;
-
- begin
- GetItemRect(win, drawWhere, tempRect);
- case whichMask of
- 1: { Star }
- begin
- vMid := tempRect.top + (tempRect.bottom - tempRect.top) div 2;
- hMid := tempRect.left + (tempRect.right - tempRect.left) div 2;
- MoveTo(hMid, tempRect.top);
- LineTo(hMid+4, vMid-4);
- LineTo(tempRect.right, vMid);
- LineTo(hMid+4, vMid+4);
- LineTo(hMid, tempRect.bottom);
- LineTo(hMid-4, vMid+4);
- LineTo(tempRect.left, vMid);
- LineTo(hMid-4, vMid-4);
- LineTo(hMid, tempRect.top);
- end;
- 2: { Square in middle }
- begin
- InsetRect(tempRect, 10, 10);
- FrameRect(tempRect);
- end;
- 3: { Concentric Squares }
- begin
- tempRect2 := tempRect;
- while (tempRect2.right - tempRect2.left) > 2 do
- begin
- FrameRect(tempRect2);
- InsetRect(tempRect2, 2, 2);
- end;
- end;
- {CASE} end;
- end;
-
- { FullScreenDemo fades the whole screen to black, then to picture one
- { then to picture two and finally to the original screen (which is
- { saved in a GWorld).
- }
- Procedure FullScreenDemo(pict1,pict2: GWorldPtr; fadeSpeed: integer);
-
- Var
- myErr: OSErr;
- theScreen: GWorldPtr;
- myPort: CGrafPtr;
- savedPort: CGrafPtr;
- savedDevice: GDHandle;
-
- begin
- { If Color QuickDraw is not available, don't do this. }
- if not HasColorQuickDraw then
- exit(FullScreenDemo);
- { Save the current port and device. }
- GetGWorld(savedPort, savedDevice);
- { Open a port that covers the main screen. OpenCPort, by default,
- { makes the port the same size as the main screen. }
- New(myPort);
- OpenCPort(myPort);
- SetGWorld(myPort, NIL);
- { Make a GWorld to store the current screen picture in. }
- myErr := NewGWorld(theScreen, 0, myPort^.portRect, NIL, NIL, 0);
- if myErr <> NoErr then
- begin
- CloseCPort(myPort);
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- { Copy the screen picture into the GWorld. }
- CopyBits(WinBitMap(myPort), WinBitMap(theScreen),
- myPort^.portRect, theScreen^.portRect, srcCopy, NIL);
- { Now fade the screen to black. }
- FadeToBlack2(WindowPtr(myPort), myPort^.portRect, fadeSpeed);
- { Slide the first image in from the left. }
- if not LockPixels(GetGWorldPixMap(pict1)) then;
- Slide(WindowPtr(pict1), pict1^.portRect,
- WindowPtr(myPort), myPort^.portRect, fadeSpeed, kLeft);
- UnlockPixels(GetGWorldPixMap(pict1));
- { Fade the second image in. }
- FadeToImage(pict2, pict2^.portRect, WindowPtr(myPort),
- myPort^.portRect, fadeSpeed);
- { Slide the original screen back in from the right. }
- if not LockPixels(GetGWorldPixMap(theScreen)) then;
- Slide(WindowPtr(theScreen), theScreen^.portRect,
- WindowPtr(myPort), myPort^.portRect, fadeSpeed, kRight);
- UnlockPixels(GetGWorldPixMap(theScreen));
- { Now get rid of the GWorld we used to hold the screen image. }
- DisposeGWorld(theScreen);
- { Close the port. }
- CloseCPort(myPort);
- { Restore the saved port and device. }
- SetGWorld(savedPort, savedDevice);
- end;
-
- { DoTechDemo brings up a new dialog that allows you to experiment
- { with all the different ways of using CopyBits, CopyMask, and
- { CopyDeepMask with different source images and masks.
- }
- Procedure DoTechDemo;
-
- Var
- demoDlg: DialogPtr;
- itemHit: integer;
- myEvent: EventRecord;
- aDlg: DialogPtr;
- sourceRect: rect;
- destRect: rect;
- opColorRect: rect;
- maskRect: rect;
- maskRegion: RgnHandle;
- copyMode: integer; { transfer mode }
- ditherAdd: integer;
- hiliteAdd: integer;
- saveColor: RGBColor;
- tempRect: rect;
- maskSet: Boolean;
- maskGWorld: GWorldPtr; { to hold a pixel map mask }
-
- begin
- { Load the main (only) dialog and display it on screen. This
- { automatically displays our two source PICTS. Since there is
- { a 'dctb' (Dialog Color Table) resource with the same ID
- { as the dialog, the Dialog Manager uses NewColorDialog to
- { make the dialog, thus giving us a color drawing port. }
- demoDlg := GetNewDialog(kTechDemoDlgID, NIL, WindowPtr(-1));
- if demoDlg = NIL then
- begin
- DoAlertStrID(kAlertDialogID, true, kMemoryOut);
- ExitToShell;
- end;
- ShowWindow(demoDlg);
- { Make sure the demo dialog is the current port. }
- SetGWorld(CGrafPtr(demoDlg), NIL);
- { Set controls to defaults. }
- SetRadioButton(demoDlg, kTechDemoSourceFirst,
- kTechDemoSourceLast, kTechDemoSourceFirst); { first source image }
- SetRadioButton(demoDlg, kTechDemoMaskFirst,
- kTechDemoMaskLast, kTechDemoMaskLast); { no mask image }
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst); { srcCopy xfer mode }
- SetOnOff(demoDlg, kTechDemoDither, false); { no dither }
- SetOnOff(demoDlg, kTechDemoHilite, false); { no hilite }
- SetRadioButton(demoDlg, kTechDemoOpColorFirst,
- kTechDemoOpColorLast, kTechDemoOpColorLast); { black OpColor }
- SetRadioButton(demoDlg, kTechDemoMaskRFirst,
- kTechDemoMaskRLast, kTechDemoMaskRLast); { no mask region }
- { Set default CopyBits parameters. }
- GetItemRect(demoDlg, kTechDemoSourcePict1, sourceRect);
- GetItemRect(demoDlg, kTechDemoDestPict, destRect);
- GetItemRect(demoDlg, kTechDemoOpColorPict, opColorRect);
- maskSet := false;
- copyMode := srcCopy;
- hiliteAdd := 0;
- ditherAdd := 0;
- maskRegion := NIL;
- { Create a GWorld to hold the pixel map mask for CopyMask and CopyDeepMask.
- { Note that I do this because when I just used the image already in the
- { dialog (without copying it to its own bitmap), things did not work
- { correctly. Apparently, the mask has to be in a separate bit/pixmap from
- { the source and destination images. }
- SetRect(maskRect, 0, 0, 50, 50);
- if NewGWorld(maskGWorld, 0, maskRect, NIL, NIL, 0) <> noErr then
- begin
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- { Paint the OpColor pict black since that's the default setting. }
- PaintRect(opColorRect);
- { Erase the destination rectangle and draw rectangles around the
- { OpColor, destination, and mask region areas. }
- EraseRect(destRect);
- tempRect := destRect;
- InsetRect(tempRect, -1, -1);
- FrameRect(tempRect);
- GetItemRect(demoDlg, kTechDemoOpColorPict, tempRect);
- InsetRect(tempRect, -1, -1);
- FrameRect(tempRect);
- GetItemRect(demoDlg, kTechDemoMaskRPict1, tempRect);
- InsetRect(tempRect, -1, -1);
- FrameRect(tempRect);
- GetItemRect(demoDlg, kTechDemoMaskRPict2, tempRect);
- InsetRect(tempRect, -1, -1);
- FrameRect(tempRect);
- GetItemRect(demoDlg, kTechDemoMaskRPict3, tempRect);
- InsetRect(tempRect, -1, -1);
- FrameRect(tempRect);
- { Draw in the mask regions in the dialog. }
- DrawMaskRegion(demoDlg, kTechDemoMaskRPict1, 1);
- DrawMaskRegion(demoDlg, kTechDemoMaskRPict2, 2);
- DrawMaskRegion(demoDlg, kTechDemoMaskRPict3, 3);
- { Now wait for the user to press a control in the dialog. }
- itemHit := -1;
- while itemHit <> kTechDemoDone do
- begin
- if WaitNextEvent(everyEvent, myEvent, GetCaretTime, NIL) then;
- { Check for disk events (bad disk mount). }
- if (myEvent.what = diskEvt) and
- (HiWord(myEvent.message) <> noErr) then
- Err := DIBadMount(dlgUpLeftCorner, myEvent.message); { ignore result }
- { Pass the event to DialogSelect which takes care of tracking
- { controls and updating everything (except the destination
- { area) for us. }
- if DialogSelect(myEvent, aDlg, itemHit) then
- begin
- { What we do here depends on what the user clicked }
- if aDlg = demoDlg then
- case itemHit of
- { These radio buttons change the source rectangle. }
- kTechDemoSourceFirst,
- kTechDemoSourcePict1:
- begin
- SetRadioButton(demoDlg, kTechDemoSourceFirst,
- kTechDemoSourceLast, kTechDemoSourceFirst);
- GetItemRect(demoDlg, kTechDemoSourcePict1, sourceRect);
- end;
- kTechDemoSourceFirst+1,
- kTechDemoSourcePict2:
- begin
- SetRadioButton(demoDlg, kTechDemoSourceFirst,
- kTechDemoSourceLast, kTechDemoSourceFirst+1);
- GetItemRect(demoDlg, kTechDemoSourcePict2, sourceRect);
- end;
- kTechDemoSourceFirst+2,
- kTechDemoSourcePict3:
- begin
- SetRadioButton(demoDlg, kTechDemoSourceFirst,
- kTechDemoSourceLast, kTechDemoSourceFirst+2);
- GetItemRect(demoDlg, kTechDemoSourcePict3, sourceRect);
- end;
- kTechDemoSourceFirst+3,
- kTechDemoSourcePict4:
- begin
- SetRadioButton(demoDlg, kTechDemoSourceFirst,
- kTechDemoSourceLast, kTechDemoSourceFirst+3);
- GetItemRect(demoDlg, kTechDemoSourcePict4, sourceRect);
- end;
- kTechDemoSourceLast,
- kTechDemoSourcePict5:
- begin
- SetRadioButton(demoDlg, kTechDemoSourceFirst,
- kTechDemoSourceLast, kTechDemoSourceLast);
- GetItemRect(demoDlg, kTechDemoSourcePict5, sourceRect);
- end;
- { These radio buttons change the mask for CopyMask. Each of
- { the first three copy the mask image shown in the dialog
- { into an offscreen GWorld (maskGWorld) to be used as the mask.
- { The fourth is the setting for no mask. }
- kTechDemoMaskPict1,
- kTechDemoMaskPict2,
- kTechDemoMaskPict3,
- kTechDemoMaskFirst,
- kTechDemoMaskFirst+1,
- kTechDemoMaskFirst+2:
- begin
- if itemHit = kTechDemoMaskPict1 then
- itemHit := kTechDemoMaskFirst
- else if itemHit = kTechDemoMaskPict2 then
- itemHit := kTechDemoMaskFirst+1
- else if itemHit = kTechDemoMaskPict3 then
- itemHit := kTechDemoMaskFirst+2;
- { Set the proper radio button. }
- SetRadioButton(demoDlg, kTechDemoMaskFirst,
- kTechDemoMaskLast, itemHit);
- { Get the rectangle of the selected mask image. }
- GetItemRect(demoDlg,
- kTechDemoMaskPict1 + itemHit - kTechDemoMaskFirst,
- tempRect);
- { Lock the mask GWorld's pixels and make it the current port. }
- if not LockPixels(GetGWorldPixMap(maskGWorld)) then;
- SetGWorld(CGrafPtr(maskGWorld), NIL);
- { Copy the mask image from the dialog to the GWorld. }
- CopyBits(WinBitMap(demoDlg), WinBitMap(maskGWorld),
- tempRect, maskRect, srcCopy, NIL);
- { Make the dialog the current port again. }
- SetGWorld(CGrafPtr(demoDlg), NIL);
- { Unlock the GWorld's pixels. }
- UnlockPixels(GetGWorldPixMap(maskGWorld));
- { There is a mask to use. }
- maskSet := true;
- end;
- kTechDemoMaskLast,
- kTechDemoMaskNone:
- begin
- SetRadioButton(demoDlg, kTechDemoMaskFirst,
- kTechDemoMaskLast, kTechDemoMaskLast);
- maskSet := false;
- if maskRegion <> NIL then
- begin
- DisposeRgn(maskRegion);
- maskRegion := NIL;
- end;
- end;
- { These radio buttons change the OpColor. }
- kTechDemoOpColorFirst:
- begin
- SetRadioButton(demoDlg, kTechDemoOpColorFirst,
- kTechDemoOpColorLast, kTechDemoOpColorFirst);
- OpColor(colors[kWhite]);
- GetForeColor(saveColor);
- RGBForeColor(colors[kWhite]);
- PaintRect(opColorRect);
- RGBForeColor(saveColor);
- end;
- kTechDemoOpColorFirst+1:
- begin
- SetRadioButton(demoDlg, kTechDemoOpColorFirst,
- kTechDemoOpColorLast, kTechDemoOpColorFirst+1);
- OpColor(colors[kLtGray]);
- GetForeColor(saveColor);
- RGBForeColor(colors[kLtGray]);
- PaintRect(opColorRect);
- RGBForeColor(saveColor);
- end;
- kTechDemoOpColorFirst+2:
- begin
- SetRadioButton(demoDlg, kTechDemoOpColorFirst,
- kTechDemoOpColorLast, kTechDemoOpColorFirst+2);
- OpColor(colors[kGray]);
- GetForeColor(saveColor);
- RGBForeColor(colors[kGray]);
- PaintRect(opColorRect);
- RGBForeColor(saveColor);
- end;
- kTechDemoOpColorFirst+3:
- begin
- SetRadioButton(demoDlg, kTechDemoOpColorFirst,
- kTechDemoOpColorLast, kTechDemoOpColorFirst+3);
- OpColor(colors[kDkGray]);
- GetForeColor(saveColor);
- RGBForeColor(colors[kDkGray]);
- PaintRect(opColorRect);
- RGBForeColor(saveColor);
- end;
- kTechDemoOpColorLast:
- begin
- SetRadioButton(demoDlg, kTechDemoOpColorFirst,
- kTechDemoOpColorLast, kTechDemoOpColorLast);
- OpColor(colors[kBlack]);
- GetForeColor(saveColor);
- RGBForeColor(colors[kBlack]);
- PaintRect(opColorRect);
- RGBForeColor(saveColor);
- end;
- { These radio buttons change the transfer mode. }
- kTechDemoModeFirst:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst);
- copyMode := srcCopy;
- end;
- kTechDemoModeFirst+1:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+1);
- copyMode := srcOr;
- end;
- kTechDemoModeFirst+2:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+2);
- copyMode := srcXor;
- end;
- kTechDemoModeFirst+3:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+3);
- copyMode := srcBic;
- end;
- kTechDemoModeFirst+4:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+4);
- copyMode := notSrcCopy;
- end;
- kTechDemoModeFirst+5:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+5);
- copyMode := notSrcOr;
- end;
- kTechDemoModeFirst+6:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+6);
- copyMode := notSrcXor;
- end;
- kTechDemoModeFirst+7:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+7);
- copyMode := notSrcBic;
- end;
- kTechDemoModeFirst+8:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+8);
- copyMode := blend;
- end;
- kTechDemoModeFirst+9:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+9);
- copyMode := addPin;
- end;
- kTechDemoModeFirst+10:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+10);
- copyMode := addOver;
- end;
- kTechDemoModeFirst+11:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+11);
- copyMode := subPin;
- end;
- kTechDemoModeFirst+12:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+12);
- copyMode := transparent;
- end;
- kTechDemoModeFirst+13:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+13);
- copyMode := addMax;
- end;
- kTechDemoModeFirst+14:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeFirst+14);
- copyMode := subOver;
- end;
- kTechDemoModeLast:
- begin
- SetRadioButton(demoDlg, kTechDemoModeFirst,
- kTechDemoModeLast, kTechDemoModeLast);
- copyMode := adMin;
- end;
- { These check boxes change the transfer mode. }
- kTechDemoDither:
- begin
- Toggle(demoDlg, kTechDemoDither);
- if GetOnOff(demoDlg, kTechDemoDither) then
- ditherAdd := ditherCopy
- else
- ditherAdd := 0;
- end;
- kTechDemoHilite:
- begin
- Toggle(demoDlg, kTechDemoHilite);
- if GetOnOff(demoDlg, kTechDemoHilite) then
- hiliteAdd := hilite
- else
- hiliteAdd := 0;
- end;
- { These buttons set the mask region. }
- kTechDemoMaskRPict1,
- kTechDemoMaskRPict2,
- kTechDemoMaskRPict3,
- kTechDemoMaskRFirst,
- kTechDemoMaskRFirst+1,
- kTechDemoMaskRFirst+2:
- begin
- { Translate clicks on the mask regions to the
- { actual radio buttons. }
- if itemHit = kTechDemoMaskRPict1 then
- itemHit := kTechDemoMaskRFirst
- else if itemHit = kTechDemoMaskRPict2 then
- itemHit := kTechDemoMaskRFirst+1
- else
- itemHit := kTechDemoMaskRFirst+2;
- SetRadioButton(demoDlg, kTechDemoMaskRFirst,
- kTechDemoMaskRLast, itemHit);
- if maskRegion <> NIL then
- DisposeRgn(maskRegion);
- maskRegion := NewRgn;
- OpenRgn;
- if itemHit = kTechDemoMaskRFirst then
- DrawMaskRegion(demoDlg, kTechDemoDestPict, 1)
- else if itemHit = kTechDemoMaskRFirst+1 then
- DrawMaskRegion(demoDlg, kTechDemoDestPict, 2)
- else
- DrawMaskRegion(demoDlg, kTechDemoDestPict, 3);
- CloseRgn(maskRegion);
- end;
- kTechDemoMaskRLast,
- kTechDemoMaskRNone:
- begin
- SetRadioButton(demoDlg, kTechDemoMaskRFirst,
- kTechDemoMaskRLast, kTechDemoMaskRLast);
- DisposeRgn(maskRegion);
- maskRegion := NIL;
- end;
- { These buttons take some action. }
- kTechDemoCopyBits:
- CopyBits(WinBitMap(demoDlg), WinBitMap(demoDlg),
- sourceRect, destRect,
- copyMode + ditherAdd + hiliteAdd, maskRegion);
- kTechDemoCopyMask:
- if maskSet then
- begin
- { Lock the mask GWorld's pixelMap. }
- if not LockPixels(GetGWorldPixMap(maskGWorld)) then;
- { CopyMask to the destination. }
- CopyMask(WinBitMap(demoDlg),
- WinBitMap(maskGWorld),
- WinBitMap(demoDlg),
- sourceRect, maskRect, destRect);
- { Unlock the mask GWorld's pixel map. }
- UnlockPixels(GetGWorldPixMap(maskGWorld));
- end
- else
- CopyBits(WinBitMap(demoDlg), WinBitMap(demoDlg), sourceRect,
- destRect, srcCopy, NIL);
- kTechDemoCopyDeepMask:
- if maskSet then
- begin
- { Lock the mask GWorld's pixelMap. }
- if not LockPixels(GetGWorldPixMap(maskGWorld)) then;
- { CopyDeepMask to the destination. }
- CopyDeepMask(WinBitMap(demoDlg),
- WinBitMap(maskGWorld),
- WinBitMap(demoDlg),
- sourceRect, maskRect,
- destRect,
- copyMode + ditherAdd + hiliteAdd,
- maskRegion);
- { Unlock the mask GWorld's pixel map. }
- UnlockPixels(GetGWorldPixMap(maskGWorld));
- end
- else
- CopyBits(WinBitMap(demoDlg), WinBitMap(demoDlg),
- sourceRect, destRect,
- copyMode + ditherAdd + hiliteAdd, NIL);
- kTechDemoErase:
- EraseRect(destRect);
- kTechDemoDone:
- { Close the demo dialog. }
- DisposeDialog(demoDlg);
- {CASE} end;
- end;
- end;
- { Reset the OpColor to black }
- OpColor(colors[kBlack]);
- { Dispose of the maskGWorld. }
- DisposeGWorld(maskGWorld);
- { Dispose of the mask region if one was set. }
- if maskRegion <> NIL then
- DisposeRgn(maskRegion);
- end;
-
- begin
- { Create some colors (white, 3 grays, and black). }
- colors[0].red := $0FFFF; { white }
- colors[0].green := $0FFFF;
- colors[0].blue := $0FFFF;
- colors[1].red := trunc($0FFFF * 0.75); { lt gray }
- colors[1].green := trunc($0FFFF * 0.75);
- colors[1].blue := trunc($0FFFF * 0.75);
- colors[2].red := trunc($0FFFF * 0.5); { gray }
- colors[2].green := trunc($0FFFF * 0.5);
- colors[2].blue := trunc($0FFFF * 0.5);
- colors[3].red := trunc($0FFFF * 0.25); { dk gray }
- colors[3].green := trunc($0FFFF * 0.25);
- colors[3].blue := trunc($0FFFF * 0.25);
- colors[4].red := 0; { black }
- colors[4].green := 0;
- colors[4].blue := 0;
- { Make sure the main monitor is using a 5 bits per color inverse
- table rather than the default 4. This will make CopyBits
- operations using arithmetic transfer modes a bit more smooth
- (but uses a little more memory). }
- aDevice := GetGDevice;
- SetGDevice(GetMainDevice);
- MakeITable(NIL, NIL, 5);
- SetGDevice(aDevice);
- { Initialize the Mac Toolbox }
- InitToolbox;
- { Check the system version. This project requires System 7
- or later for the GWorlds.}
- if GetSysVersion < 7 then
- begin
- DoAlertStrID(kAlertDialogID, true, kSys7Required);
- ExitToShell;
- end;
- {
- { Load the main dialog and display it on screen. This
- { automatically displays our two source PICTS. Since there is
- { a 'dctb' (Dialog Color Table) resource with the same ID
- { as the dialog, the Dialog Manager uses NewColorDialog to
- { make the dialog, thus giving us a color drawing port.
- { In ResEdit, creating a 'dctb' resource for a dialog is as
- { easy as clicking Custom for the color scheme rather than
- { default when you have the 'DLOG' resource open.
- }
- mainDlg:= GetNewDialog(kMainDlgID, NIL, WindowPtr(-1));
- if mainDlg = NIL then
- begin
- DoAlertStrID(kAlertDialogID, true, kMemoryOut);
- ExitToShell;
- end;
- { Select the text in the fade speed text edit box. }
- SelectTextField(mainDlg, kMainDlgFadeSpeed);
- { Make sure the dialog is visible and that it's the current port. }
- ShowWindow(mainDlg);
- SetGWorld(CGrafPtr(mainDlg), NIL);
- {
- { Get the picture rectangles and the destination picture's
- { rectangle. Save them for later use.
- }
- GetItemRect(mainDlg, kMainDlgPICTOne, pict1Rect);
- GetItemRect(mainDlg, kMainDlgPICTTwo, pict2Rect);
- GetItemRect(mainDlg, kMainDlgDestPICT, destRect);
- {
- { Draw a box around each of the picture areas to better
- { define them on screen.
- }
- tempRect := destRect;
- InsetRect(tempRect, -1, -1);
- FrameRect(tempRect);
- tempRect := pict1Rect;
- InsetRect(tempRect, -1, -1);
- FrameRect(tempRect);
- tempRect := pict2Rect;
- InsetRect(tempRect, -1, -1);
- FrameRect(tempRect);
- {
- { Draw each of the two "source" pictures into an offscreen
- { Graphics World for use later. For example, when the user
- { passes the cursor over the left picture, regular animation
- { techniques are used to make a circle "float" above the
- { picture (causes flicker). This involves repeatedly
- { copying the original picture to the window, then drawing
- { the circle over it. When the user passes the cursor over
- { the right picture, the original picture is drawn to an
- { offscreen gworld and the circle is drawn over it, then
- { that image is drawn to the window resulting in flicker-free
- { animation of the floating circle.
- {
- { We need the two gworlds here so we have the original
- { pictures to copy from.
- { Load picture 1 from resource.
- }
- aPict := GetPicture(kPict1ID);
- if aPict = NIL then
- begin
- DoAlertStrID(kAlertDialogID, true, kMissingResource);
- ExitToShell;
- end;
- { Get it's optimum rectangle. }
- myErr := GetPictInfo(aPict, myPictInfo, 0, 0, 0, 0);
- pict1GRect := myPictInfo.sourceRect;
- { Release any extra items GetPictInfo may have allocated }
- { if we're not going to use them. }
- if myPictInfo.commentHandle <> NIL then
- DisposeHandle(Handle(myPictInfo.commentHandle));
- if myPictInfo.fontHandle <> NIL then
- DisposeHandle(Handle(myPictInfo.fontHandle));
- { Make a GWorld for the picture. }
- myErr := NewGWorld(pict1GWorld, 0, pict1GRect, NIL, NIL, 0);
- if (myErr <> NoErr) | (pict1GWorld = NIL) then
- begin
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- { Lock the GWorld's pixels and draw the picture into it. }
- if not LockPixels(GetGWorldPixMap(pict1GWorld)) then;
- SetGWorld(CGrafPtr(pict1GWorld), NIL);
- PaintRect(pict1GRect); { first paint it all black }
- DrawPicture(aPict, pict1GRect);
- UnlockPixels(GetGWorldPixMap(pict1GWorld));
- { Load picture 2 from resource. }
- aPict := GetPicture(kPict2ID);
- if aPict = NIL then
- begin
- DoAlertStrID(kAlertDialogID, true, kMissingResource);
- ExitToShell;
- end;
- { Get it's optimum rectangle. }
- myErr := GetPictInfo(aPict, myPictInfo, 0, 0, 0, 0);
- pict2GRect := myPictInfo.sourceRect;
- { Release any extra items GetPictInfo may have allocated }
- { if we're not going to use them. }
- if myPictInfo.commentHandle <> NIL then
- DisposeHandle(Handle(myPictInfo.commentHandle));
- if myPictInfo.fontHandle <> NIL then
- DisposeHandle(Handle(myPictInfo.fontHandle));
- { Make a GWorld for the picture. }
- myErr := NewGWorld(pict2GWorld, 0, pict2GRect, NIL, NIL, 0);
- if (myErr <> NoErr) | (pict2GWorld = NIL) then
- begin;
- DoAlertStrID(kAlertDialogID, true, kGWorldErr);
- ExitToShell;
- end;
- { Lock the GWorld's pixels and draw the picture into it. }
- if not LockPixels(GetGWorldPixMap(pict2GWorld)) then;
- SetGWorld(CGrafPtr(pict2GWorld), NIL);
- PaintRect(pict2GRect); { first paint it all black }
- DrawPicture(aPict, pict2GRect);
- UnlockPixels(GetGWorldPixMap(pict2GWorld));
- { Make sure and restore the dialog as the current port. }
- SetGWorld(CGrafPtr(mainDlg), NIL);
- { Now wait for the user to press a button in the dialog. }
- itemHit := -1;
- while itemHit <> kMainDlgQuit do
- begin
- if WaitNextEvent(everyEvent, myEvent, GetCaretTime(), NIL) then;
- { Check for disk events (bad disk mount). }
- if (myEvent.what = diskEvt) & (HiWord(myEvent.message) <> noErr) then
- begin
- SetPt(dlgUpLeftCorner,100,80);
- Err := DIBadMount(dlgUpLeftCorner, myEvent.message); { ignore result }
- end
- { If we get an update event, redraw the squares around the }
- { picture areas. }
- else if (myEvent.what = updateEvt) then
- begin
- tempRect := destRect;
- InsetRect(tempRect, -1, -1);
- FrameRect(tempRect);
- tempRect := pict1Rect;
- InsetRect(tempRect, -1, -1);
- FrameRect(tempRect);
- tempRect := pict2Rect;
- InsetRect(tempRect, -1, -1);
- FrameRect(tempRect);
- end;
- {
- { If the mouse is over one of the pictures, call a routine
- { to animate a "floating circle" over the picture. A
- { different method is used for each picture to demonstrate
- { the differences.
- }
- GetMouse(mouseLoc);
- if PtInRect(mouseLoc, pict1Rect) then
- FlickerAnimate(pict1GWorld, pict1Rect)
- else if PtInRect(mouseLoc, pict2Rect) then
- SmoothAnimate(pict2GWorld, pict2Rect);
- {
- { Pass the event to DialogSelect which takes care of tracking
- { controls and updating everything (except the destination
- { area) for us.
- }
- if DialogSelect(myEvent, aDlg, itemHit) then
- begin
- if myEvent.what = mouseDown then
- begin
- { Select the fade speed text field. }
- SelectTextField(mainDlg, kMainDlgFadeSpeed);
- { Get the fade speed from the dialog (as a number). }
- fadeSpeed := GetDialogNumberField(mainDlg, kMainDlgFadeSpeed);
- end;
- { What we do here depends on what the user clicked }
- case itemHit of
- kMainDlgCopyOne:
- begin
- {
- { This is an example of a very courteous CopyBits
- { operation saving and restoring the pen state as
- { well as the fore and background colors and restoring
- { them afterwards. I don't really need to do this here
- { because I know they're all set right in the first
- { place, but they're here as an example.
-
- { Save the pen state and foreground/background colors
- }
- GetPenState(savedPen);
- GetForeColor(savedFore);
- GetBackColor(savedBack);
- { Set foreground color to black, background color to white }
- RGBForeColor(colors[kBlack]);
- RGBBackColor(colors[kWhite]);
- { Just use CopyBits to copy the PICT. We're actually }
- { copying from one place on the dialog to another here. }
- CopyBits(WinBitMap(mainDlg), WinBitMap(mainDlg),
- pict1Rect, destRect, srcCopy, NIL);
- { Restore the saved pen state and colors }
- SetPenState(savedPen);
- RGBForeColor(savedFore);
- RGBBackColor(savedBack);
- end;
- kMainDlgFadeOne:
- { Call FadeToImage to fade picture 1 into the }
- { destination area. }
- FadeToImage(pict1GWorld, pict1GWorld^.portRect,
- mainDlg, destRect, fadeSpeed);
- kMainDlgCopyTwo:
- { Just use CopyBits to copy the PICT from one place in }
- { the window to another. }
- CopyBits(WinBitMap(mainDlg), WinBitMap(mainDlg),
- pict2Rect, destRect, srcCopy, NIL);
- kMainDlgFadeTwo:
- { Call FadeToImage to fade picture 2 into the }
- { destination area. }
- FadeToImage(pict2GWorld, pict2GWorld^.portRect,
- mainDlg, destRect, fadeSpeed);
- kMainDlgErase:
- { Erase the destination area. }
- EraseRect(destRect);
- kMainDlgFadeToBlack1:
- { Call FadeToBlack to fade the destination rectangle. }
- FadeToBlack1(mainDlg, destRect, fadeSpeed);
- kMainDlgFadeToBlack2:
- { Call FadeToBlack to fade the destination rectangle. }
- FadeToBlack2(mainDlg, destRect, fadeSpeed);
- kMainDlgFadeToBlack3:
- { Call FadeToBlack to fade the destination rectangle. }
- FadeToBlack3(mainDlg, destRect, fadeSpeed);
- kMainDlgPixelize:
- { Call Pixelize. }
- Pixelize(mainDlg, destRect,
- mainDlg, destRect, fadeSpeed, true);
- kMainDlgDepixelizeOne:
- begin
- { Call Pixelize. }
- if not LockPixels(GetGWorldPixMap(pict1GWorld)) then;
- Pixelize(WindowPtr(pict1GWorld), pict1GWorld^.portRect,
- mainDlg, destRect, fadeSpeed, false);
- UnlockPixels(GetGWorldPixMap(pict1GWorld));
- end;
- kMainDlgDepixelizeTwo:
- begin
- { Call Pixelize. }
- if not LockPixels(GetGWorldPixMap(pict2GWorld)) then;
- Pixelize(WindowPtr(pict2GWorld), pict2GWorld^.portRect,
- mainDlg, destRect, fadeSpeed, false);
- UnlockPixels(GetGWorldPixMap(pict2GWorld));
- end;
- kMainDlgFullScreen:
- { Fade full screen to black, then image 1, then image 2, }
- { then back to original. }
- FullScreenDemo(pict1GWorld, pict2GWorld, fadeSpeed);
- kMainDlgBlur:
- { Blur the destination area. }
- Blur(WindowPtr(mainDlg), destRect);
- kMainDlgFlipHoriz:
- { Flip the destination area horizontally. }
- FlipHorizontal(WindowPtr(mainDlg), destRect);
- kMainDlgFlipVert:
- { Flip the destination area horizontally. }
- FlipVertical(WindowPtr(mainDlg), destRect);
- kMainDlgSlideL:
- begin
- { Slide picture one into destination from left. }
- if not LockPixels(GetGWorldPixMap(pict1GWorld)) then;
- Slide(WindowPtr(pict1GWorld), pict1GWorld^.portRect,
- mainDlg, destRect, fadeSpeed, kLeft);
- UnlockPixels(GetGWorldPixMap(pict1GWorld));
- end;
- kMainDlgSlideR:
- begin
- { Slide picture one into destination from right. }
- if not LockPixels(GetGWorldPixMap(pict1GWorld)) then;
- Slide(WindowPtr(pict1GWorld), pict1GWorld^.portRect,
- mainDlg, destRect, fadeSpeed, kRight);
- UnlockPixels(GetGWorldPixMap(pict1GWorld));
- end;
- kMainDlgSlideT:
- begin
- { Slide picture one into destination from top. }
- if not LockPixels(GetGWorldPixMap(pict1GWorld)) then;
- Slide(WindowPtr(pict1GWorld), pict1GWorld^.portRect,
- mainDlg, destRect, fadeSpeed, kTop);
- UnlockPixels(GetGWorldPixMap(pict1GWorld));
- end;
- kMainDlgSlideB:
- begin
- { Slide picture one into destination from bottom. }
- if not LockPixels(GetGWorldPixMap(pict1GWorld)) then;
- Slide(WindowPtr(pict1GWorld), pict1GWorld^.portRect,
- mainDlg, destRect, fadeSpeed, kBottom);
- UnlockPixels(GetGWorldPixMap(pict1GWorld));
- end;
- kMainDlgApertureIn:
- begin
- { Close a circle in on the destination revealing }
- { picture two outside the circle. }
- if not LockPixels(GetGWorldPixMap(pict2GWorld)) then;
- Aperture(WindowPtr(pict2GWorld), pict2GWorld^.portRect,
- mainDlg, destRect, fadeSpeed, kIn);
- UnlockPixels(GetGWorldPixMap(pict2GWorld));
- end;
- kMainDlgApertureOut:
- begin
- { Open a circle out on the destination revealing }
- { picture two inside the circle. }
- if not LockPixels(GetGWorldPixMap(pict2GWorld)) then;
- Aperture(WindowPtr(pict2GWorld), pict2GWorld^.portRect,
- mainDlg, destRect, fadeSpeed, kOut);
- UnlockPixels(GetGWorldPixMap(pict2GWorld));
- end;
- kMainDlgTechDemo:
- begin
- { Open the technical demo window and let the user mess around. }
- DoTechDemo;
- { Make sure the current port is set back to the main dialog. }
- SetGWorld(CGrafPtr(mainDlg), NIL);
- end;
- {CASE} end;
- end;
- end;
- { Get rid of the main dialog. }
- DisposeDialog(mainDlg);
- { Restore the main monitor's inverse table to 4 bits per }
- { color (which is the default). }
- aDevice := GetGDevice;
- SetGDevice(GetMainDevice());
- MakeITable(NIL, NIL, 4);
- SetGDevice(aDevice);
- end.
-
-